package net.atomarrow.util.excel;

/* ====================================================================
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 ==================================================================== */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Color;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;

/**
 * 自定义单元格样式，该样式可以控制单元格的样式，但该类对象的生成完全脱离POI, 可以由用户创建，使用规范和POI的HSSFCellStyle完全相同
 * 
 * 
 */

public final class SimpleHSSFCellStyle implements CellStyle {

	private HSSFCellStyle style;
	private HSSFFont font;
	private Boolean hidden;
	private Boolean locked;
	private Short alignment;
//	private Boolean setWrapText;
	private Short verticalAlignment;
	private Short rotation;
	private Short indention;
	private Short borderLeft;
	private Short borderRight;
	private Short borderTop;
	private Short borderBottom;
	private Short leftBorderColor;
	private Short rightBorderColor;
	private Short topBorderColor;
	private Short bottomBorderColor;
	private Short fillPattern;
	private Short fillBackgroundColor;
	private Short fillForegroundColor;
	private String userStyleName;
	private Boolean wrapText;
	private Short dataFormat;
	private SimpleHSSFFont simpleHSSFFont;
	/**
	 * 无样式类型
	 */
	public static final int STYLE_MODEL_NONE = 0;
	/**
	 * 大标题样式类型
	 */
	public static final int STYLE_MODEL_TITLE = 1;
	/**
	 * 表头样式类型
	 */
	public static final int STYLE_MODEL_HEADER = 2;
	/**
	 * 数据内容类型
	 */
	public static final int STYLE_MODEL_DATACONTENT = 3;

	private int stytleModel = STYLE_MODEL_NONE;

	/**
	 * set the font for this style
	 * 
	 * @param font
	 *            a font object created or retreived from the HSSFWorkbook
	 *            object
	 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#createFont()
	 * @see org.apache.poi.hssf.usermodel.HSSFWorkbook#getFontAt(short)
	 */
	@Override
	public void setFont(Font font) {

		setFont((SimpleHSSFFont) font);
	}
	
	public void setFont(SimpleHSSFFont font) {
		this.simpleHSSFFont = font;
	}

	/**
	 * set the cell's using this style to be hidden
	 * 
	 * @param hidden -
	 *            whether the cell using this style should be hidden
	 */
	@Override
	public void setHidden(boolean hidden) {

		this.hidden = hidden;
	}

	/**
	 * set the cell's using this style to be locked
	 * 
	 * @param locked -
	 *            whether the cell using this style should be locked
	 */
	@Override
	public void setLocked(boolean locked) {

		this.locked = locked;

	}

	/**
	 * set the type of horizontal alignment for the cell
	 * 
	 * @param align -
	 *            the type of alignment
	 * @see #ALIGN_GENERAL
	 * @see #ALIGN_LEFT
	 * @see #ALIGN_CENTER
	 * @see #ALIGN_RIGHT
	 * @see #ALIGN_FILL
	 * @see #ALIGN_JUSTIFY
	 * @see #ALIGN_CENTER_SELECTION
	 */
	@Override
	public void setAlignment(short align) {

		this.alignment = align;
	}

	/**
	 * set whether the text should be wrapped
	 * 
	 * @param wrapped
	 *            wrap text or not
	 */
	@Override
	public void setWrapText(boolean wrapped) {

		this.wrapText = wrapped;
	}

	/**
	 * set the type of vertical alignment for the cell
	 * 
	 * @param align
	 *            the type of alignment
	 * @see #VERTICAL_TOP
	 * @see #VERTICAL_CENTER
	 * @see #VERTICAL_BOTTOM
	 * @see #VERTICAL_JUSTIFY
	 */
	@Override
	public void setVerticalAlignment(short align) {
		this.verticalAlignment = align;
	}

	/**
	 * set the degree of rotation for the text in the cell
	 * 
	 * @param rotation
	 *            degrees (between -90 and 90 degrees, of 0xff for vertical)
	 */
	@Override
	public void setRotation(short rotation) {

		this.rotation = rotation;
	}

	/**
	 * set the number of spaces to indent the text in the cell
	 * 
	 * @param indent -
	 *            number of spaces
	 */
	@Override
	public void setIndention(short indent) {
		this.indention = indent;
	}

	/**
	 * set the type of border to use for the left border of the cell
	 * 
	 * @param border
	 *            type
	 * @see #BORDER_NONE
	 * @see #BORDER_THIN
	 * @see #BORDER_MEDIUM
	 * @see #BORDER_DASHED
	 * @see #BORDER_DOTTED
	 * @see #BORDER_THICK
	 * @see #BORDER_DOUBLE
	 * @see #BORDER_HAIR
	 * @see #BORDER_MEDIUM_DASHED
	 * @see #BORDER_DASH_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT
	 * @see #BORDER_DASH_DOT_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT_DOT
	 * @see #BORDER_SLANTED_DASH_DOT
	 */
	@Override
	public void setBorderLeft(short border) {

		this.borderLeft = border;
	}

	/**
	 * set the type of border to use for the right border of the cell
	 * 
	 * @param border
	 *            type
	 * @see #BORDER_NONE
	 * @see #BORDER_THIN
	 * @see #BORDER_MEDIUM
	 * @see #BORDER_DASHED
	 * @see #BORDER_DOTTED
	 * @see #BORDER_THICK
	 * @see #BORDER_DOUBLE
	 * @see #BORDER_HAIR
	 * @see #BORDER_MEDIUM_DASHED
	 * @see #BORDER_DASH_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT
	 * @see #BORDER_DASH_DOT_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT_DOT
	 * @see #BORDER_SLANTED_DASH_DOT
	 */
	@Override
	public void setBorderRight(short border) {

		this.borderRight = border;
	}

	/**
	 * set the type of border to use for the top border of the cell
	 * 
	 * @param border
	 *            type
	 * @see #BORDER_NONE
	 * @see #BORDER_THIN
	 * @see #BORDER_MEDIUM
	 * @see #BORDER_DASHED
	 * @see #BORDER_DOTTED
	 * @see #BORDER_THICK
	 * @see #BORDER_DOUBLE
	 * @see #BORDER_HAIR
	 * @see #BORDER_MEDIUM_DASHED
	 * @see #BORDER_DASH_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT
	 * @see #BORDER_DASH_DOT_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT_DOT
	 * @see #BORDER_SLANTED_DASH_DOT
	 */
	@Override
	public void setBorderTop(short border) {

		this.borderTop = border;
	}

	/**
	 * set the type of border to use for the bottom border of the cell
	 * 
	 * @param border
	 *            type
	 * @see #BORDER_NONE
	 * @see #BORDER_THIN
	 * @see #BORDER_MEDIUM
	 * @see #BORDER_DASHED
	 * @see #BORDER_DOTTED
	 * @see #BORDER_THICK
	 * @see #BORDER_DOUBLE
	 * @see #BORDER_HAIR
	 * @see #BORDER_MEDIUM_DASHED
	 * @see #BORDER_DASH_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT
	 * @see #BORDER_DASH_DOT_DOT
	 * @see #BORDER_MEDIUM_DASH_DOT_DOT
	 * @see #BORDER_SLANTED_DASH_DOT
	 */
	@Override
	public void setBorderBottom(short border) {

		this.borderBottom = border;
	}

	/**
	 * 设置边框粗细
	 * 
	 * @param borderTop
	 *            上
	 * @param borderBottom
	 *            下
	 * @param borderLeft
	 *            左
	 * @param borderRight
	 *            右
	 */
	public void setBorder(short borderTop, short borderBottom,
			short borderLeft, short borderRight) {

		this.setBorderTop(borderTop);
		this.setBorderBottom(borderBottom);
		this.setBorderBottom(borderLeft);
		this.setBorderRight(borderRight);

	}

	/**
	 * set the color to use for the left border
	 * 
	 * @param color
	 *            The index of the color definition
	 */
	@Override
	public void setLeftBorderColor(short color) {

		this.leftBorderColor = color;
	}

	/**
	 * set the color to use for the right border
	 * 
	 * @param color
	 *            The index of the color definition
	 */
	@Override
	public void setRightBorderColor(short color) {
		this.rightBorderColor = color;
	}

	/**
	 * set the color to use for the top border
	 * 
	 * @param color
	 *            The index of the color definition
	 */
	@Override
	public void setTopBorderColor(short color) {

		this.topBorderColor = color;
	}

	/**
	 * set the color to use for the bottom border
	 * 
	 * @param color
	 *            The index of the color definition
	 */
	@Override
	public void setBottomBorderColor(short color) {
		this.bottomBorderColor = color;
	}

	/**
	 * 设置边框颜色
	 * 
	 * @param topBorderColor
	 *            上
	 * @param bottomBorderColor
	 *            下
	 * @param leftBorderColor
	 *            左
	 * @param rightBorderColor
	 *            右
	 */
	
	public void setBorderColor(short topBorderColor, short bottomBorderColor,
			short leftBorderColor, short rightBorderColor) {
		this.setTopBorderColor(topBorderColor);
		this.setBottomBorderColor(bottomBorderColor);
		this.setLeftBorderColor(leftBorderColor);
		this.setRightBorderColor(rightBorderColor);

	}

	/**
	 * setting to one fills the cell with the foreground color... No idea about
	 * other values
	 * 
	 * @see #NO_FILL
	 * @see #SOLID_FOREGROUND
	 * @see #FINE_DOTS
	 * @see #ALT_BARS
	 * @see #SPARSE_DOTS
	 * @see #THICK_HORZ_BANDS
	 * @see #THICK_VERT_BANDS
	 * @see #THICK_BACKWARD_DIAG
	 * @see #THICK_FORWARD_DIAG
	 * @see #BIG_SPOTS
	 * @see #BRICKS
	 * @see #THIN_HORZ_BANDS
	 * @see #THIN_VERT_BANDS
	 * @see #THIN_BACKWARD_DIAG
	 * @see #THIN_FORWARD_DIAG
	 * @see #SQUARES
	 * @see #DIAMONDS
	 * 
	 * @param fp
	 *            fill pattern (set to 1 to fill w/foreground color)
	 */
	@Override
	public void setFillPattern(short fp) {
		this.fillPattern = fp;
	}

	/**
	 * set the background fill color.
	 * <p>
	 * For example:
	 * 
	 * <pre>
	 * cs.setFillPattern(HSSFCellStyle.FINE_DOTS);
	 * cs.setFillBackgroundColor(new HSSFColor.RED().getIndex());
	 * </pre>
	 * 
	 * optionally a Foreground and background fill can be applied: <i>Note:
	 * Ensure Foreground color is set prior to background</i>
	 * 
	 * <pre>
	 * cs.setFillPattern(HSSFCellStyle.FINE_DOTS);
	 * cs.setFillForegroundColor(new HSSFColor.BLUE().getIndex());
	 * cs.setFillBackgroundColor(new HSSFColor.RED().getIndex());
	 * </pre>
	 * 
	 * or, for the special case of SOLID_FILL:
	 * 
	 * <pre>
	 * cs.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
	 * cs.setFillForegroundColor(new HSSFColor.RED().getIndex());
	 * </pre>
	 * 
	 * It is necessary to set the fill style in order for the color to be shown
	 * in the cell.
	 * 
	 */
	@Override
	public void setFillBackgroundColor(short bg) {

		this.fillBackgroundColor = bg;
	}

	/**
	 * set the foreground fill color <i>Note: Ensure Foreground color is set
	 * prior to background color.</i>
	 * 
	 * @param bg
	 *            color
	 */
	@Override
	public void setFillForegroundColor(short bg) {
		this.fillForegroundColor = bg;
	}

//	/**
//	 * Sets the name of the user defined style. Will complain if you try this on
//	 * a built in style.
//	 */
//	@Override
	public void setUserStyleName(String styleName) {
		this.userStyleName = styleName;
	}
//	@Override
	public HSSFCellStyle getStyle() {
		return style;
	}
	public void copyPropertiesToStyle(HSSFCellStyle style) {
		this.style = style;

		Method[] methods = style.getClass().getMethods();
		String fieldName;
		String getterName;
		Method getter;
		Object value;
		for (Method method : methods) {
			String methodName = method.getName();

			if (methodName.startsWith("set")) {
				fieldName = methodName.substring(3);
				 Class<?>[] params = method.getParameterTypes();
				 if(params[0].isEnum()){
					 fieldName=fieldName+"Enum";
				 }
				getterName = "get" + fieldName;
				try {
					getter = this.getClass().getMethod(getterName, null);
					value = getter.invoke(this, null);
					if (value != null) {

						method.invoke(style, value);
					}

				} catch (SecurityException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}
			}

		}
	}

	/**
	 * 将用户自定义的font属性赋给Workbook的font，注意，该方法一定要在copyPropertiesToStyle之前调用
	 * 
	 * @param font
	 */
	public void copyPropertiesToFont(HSSFFont font) {
		if (simpleHSSFFont != null) {

			simpleHSSFFont.copyPropertiesToStyle(font);
			this.font = font;
		}

	}
//	@Override
//	public boolean isSetWrapText() {
//		return setWrapText;
//	}
//	@Override
//	public void setSetWrapText(boolean setWrapText) {
//		this.setWrapText = setWrapText;
//	}
	@Override
	public boolean getHidden() {
		return hidden==null?style.getHidden():hidden;
	}
	@Override
	public boolean getLocked() {
		return locked==null?style.getLocked():locked;
	}
	@Override
	public short getAlignment() {
		return alignment==null?style.getAlignment():alignment;
	}
	@Override
	public short getVerticalAlignment() {
		return verticalAlignment==null?style.getVerticalAlignment():verticalAlignment;
	}
	@Override
	public short getRotation() {
		return rotation==null?style.getRotation():rotation;
	}
	@Override
	public short getIndention() {
		return indention==null?style.getIndention():indention;
	}
	@Override
	public short getBorderLeft() {
		return borderLeft==null?style.getBorderLeft():borderLeft;
	}
	@Override
	public short getBorderRight() {
		return borderRight==null?style.getBorderRight():borderRight;
	}
	@Override
	public short getBorderTop() {
		return borderTop==null?style.getBorderTop():borderTop;
	}
	@Override
	public short getBorderBottom() {
		return borderBottom==null?style.getBorderBottom():borderBottom;
	}
	@Override
	public short getLeftBorderColor() {
		return leftBorderColor==null?style.getLeftBorderColor():leftBorderColor;
	}
	@Override
	public short getRightBorderColor() {
		return rightBorderColor==null?style.getRightBorderColor():rightBorderColor;
	}
	@Override
	public short getTopBorderColor() {
		return topBorderColor==null?style.getTopBorderColor():topBorderColor;
	}
	@Override
	public short getBottomBorderColor() {
		return bottomBorderColor==null?style.getBottomBorderColor():bottomBorderColor;
	}
	@Override
	public short getFillPattern() {
		return fillPattern==null?style.getFillPattern():fillPattern;
	}
	@Override
	public short getFillBackgroundColor() {
		return fillBackgroundColor==null?style.getFillBackgroundColor():fillBackgroundColor;
	}
	@Override
	public short getFillForegroundColor() {
		return fillForegroundColor==null?style.getFillForegroundColor():fillForegroundColor;
	}
//	@Override
	public String getUserStyleName() {
		return userStyleName==null?style.getUserStyleName():userStyleName;
	}
	@Override
	public boolean getWrapText() {
		return wrapText==null?style.getWrapText():wrapText;
	}
	@Override
	public short getDataFormat() {
		return dataFormat==null?style.getDataFormat():dataFormat;
	}
	@Override
	public void setDataFormat(short dataFormat) {
		this.dataFormat = dataFormat;
	}

	@Override
	public void cloneStyleFrom(CellStyle source) {
		this.style.cloneStyleFrom(source);

	}

	@Override
	public String getDataFormatString() {
		return style.getDataFormatString();
	}

	@Override
	public Color getFillBackgroundColorColor() {
		return this.style.getFillBackgroundColorColor();
	}

	@Override
	public Color getFillForegroundColorColor() {
		return this.style.getFillBackgroundColorColor();
	}

	@Override
	public short getFontIndex() {
		return this.style.getFontIndex();
	}
	public HSSFFont getFont() {
		return font;
	}
	@Override
	public short getIndex() {
		return this.style.getIndex();
	}

	public SimpleHSSFFont getSimpleHSSFFont() {
		return simpleHSSFFont;
	}

	public void setSimpleHSSFFont(SimpleHSSFFont simpleHSSFFont) {
		this.simpleHSSFFont = simpleHSSFFont;
	}

	public int getStytleModel() {
		return stytleModel;
	}

	public void setStytleModel(int stytleModel) {
		this.stytleModel = stytleModel;
	}

	private Boolean quotePrefix;
	@Override
	public void setQuotePrefixed(boolean quotePrefix) {
		this.quotePrefix=quotePrefix;
	}

	@Override
	public boolean getQuotePrefixed() {
		return quotePrefix==null?style.getQuotePrefixed():quotePrefix;
	}

	private HorizontalAlignment horizontalAlignment;
	@Override
	public void setAlignment(HorizontalAlignment align) {
		this.horizontalAlignment=align;
	}

	@Override
	public HorizontalAlignment getAlignmentEnum() {
		return horizontalAlignment==null?style.getAlignmentEnum():horizontalAlignment;
	}

	private VerticalAlignment vAlignment;
	@Override
	public void setVerticalAlignment(VerticalAlignment align) {
		this.vAlignment=align;
	}

	@Override
	public VerticalAlignment getVerticalAlignmentEnum() {
		return vAlignment==null?style.getVerticalAlignmentEnum():vAlignment;
	}

	private BorderStyle borderLeftEnum;
	private BorderStyle borderRightEnum;
	private BorderStyle borderTopEnum;
	private BorderStyle borderBottomEnum;
	@Override
	public void setBorderLeft(BorderStyle border) {
		this.borderLeftEnum=border;
	}

	@Override
	public BorderStyle getBorderLeftEnum() {
		return borderLeftEnum==null?style.getBorderLeftEnum():borderLeftEnum;
	}

	
	@Override
	public void setBorderRight(BorderStyle border) {
		this.borderRightEnum=border;
	}

	@Override
	public BorderStyle getBorderRightEnum() {
		return borderRightEnum==null?style.getBorderRightEnum():borderRightEnum;
	}

	@Override
	public void setBorderTop(BorderStyle border) {
		this.borderTopEnum=border;
	}

	@Override
	public BorderStyle getBorderTopEnum() {
		return borderTopEnum==null?style.getBorderTopEnum():borderTopEnum;
	}

	@Override
	public void setBorderBottom(BorderStyle border) {
		this.borderBottomEnum=border;
		
	}

	@Override
	public BorderStyle getBorderBottomEnum() {
		return borderBottomEnum==null?style.getBorderBottomEnum():borderBottomEnum;
	}

	private FillPatternType fp;
	@Override
	public void setFillPattern(FillPatternType fp) {
		this.fp=fp;
	}

	@Override
	public FillPatternType getFillPatternEnum() {
		return fp==null?style.getFillPatternEnum():fp;
	}

	private Boolean shrinkToFit;
	@Override
	public void setShrinkToFit(boolean shrinkToFit) {
		this.shrinkToFit=shrinkToFit;
	}

	@Override
	public boolean getShrinkToFit() {
		return shrinkToFit==null?style.getShrinkToFit():shrinkToFit;
	}
	private Short readingOrder;
    public void setReadingOrder(short order) {
        this.readingOrder= order;
    }
    public short getReadingOrder(){
    	return readingOrder==null?style.getReadingOrder():readingOrder;
    }
}
